package com.joymart.scheduling;

import com.joymart.common.model.Range;
import com.joymart.common.utils.DatetimeUtils;
import com.joymart.compute.service.MonthlyGroupPvService;
import com.joymart.order.model.Order;
import com.joymart.order.service.OrderFlowService;
import com.joymart.prepaid.wallet.service.PrepaidWalletService;
import com.joymart.qualification.service.AdvanceEvaluationService;
import com.joymart.qualification.service.RetainEvaluationService;
import com.joymart.user.model.BusinessRole;
import com.joymart.user.repo.BusinessRoleRepository;
import com.joymart.user.service.UserCacheManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Service
public class SchedulingService {

    @Autowired
    private AdvanceEvaluationService advanceEvaluationService;
    @Autowired
    private BusinessRoleRepository businessRoleRepository;
    @Autowired
    private UserCacheManager userCacheManager;
    @Autowired
    private OrderFlowService orderFlowService;
    @Autowired
    private PrepaidWalletService prepaidWalletService;
    @Autowired
    private RetainEvaluationService retainEvaluationService;
    @Autowired
    private MonthlyGroupPvService monthlyGroupPvService;

    /**
     * 超时订单自动取消
     */
    @Scheduled(cron = "0 0 20 * * ?")
    public void autoCancelOrders(){
        log.info("Task [Auto Cancel Orders] starts");
        LocalDateTime end = DatetimeUtils.now().with(LocalTime.of(18,0));
        LocalDateTime start = end.minusDays(1);
        List<Order> timeoutOrders = orderFlowService.findTimeoutOrders(Range.of(start, end));
        timeoutOrders.forEach(orderFlowService::autoCancel);
        log.info("Task [Auto Cancel Orders] finished");
    }

    /**
     * 发货后超时订单自动签收
     */
    @Scheduled(cron = "0 0 18 * * ?")
    public void autoReceiveOrders(){
        log.info("Task [Auto Receive Orders] starts");
        LocalDateTime end = DatetimeUtils.now().with(LocalTime.of(18,0))
                .minusDays(7);
        LocalDateTime start = end.minusDays(2);
        // 9天前到7天前发货的订单
        List<Order> timeoutOrders = orderFlowService.findReceivingTimeoutOrders(Range.of(start, end));
        timeoutOrders.forEach(orderFlowService::autoReceive);
        log.info("Task [Auto Receive Orders] finished");
    }


    /**
     *  计算团队业绩并持久化（用于保级计算和合营部分的资格评估）
     */
    @Scheduled(cron = "0 0 1 1 * ?")
    public void computeMonthlyGroupPv(){
        log.info("Task [Compute Monthly Group PV] starts");
        LocalDateTime lastMonth = DatetimeUtils.now().minusMonths(1); //上个月的  monthlyGroupPvService.computeMonthlyGroupPv(month, BusinessRole.AG_WHS);
        monthlyGroupPvService.computeMonthlyGroupPv(lastMonth, BusinessRole.AG_WHS);
        monthlyGroupPvService.computeMonthlyGroupPv(lastMonth, BusinessRole.AG_AGENT);
        log.info("Task [Compute Monthly Group PV] finished");
    }



    /**
     * 月度收益转换预付货款
     */
    @Scheduled(cron = "0 0 2 10 * ?")
    public void prepaidWalletConversion(){
        log.info("Task [Prepaid wallet conversion] starts");
        Range range = DatetimeUtils.month(DatetimeUtils.now().minusMonths(1)); //上个月的
        prepaidWalletService.convertOrderGainToPrepaidWallet(range);
        log.info("Task [Prepaid wallet conversion] finished");
    }


    /**
     * 每晚进行部分运营资格的评估
     * 2-5号不进行， 以便用户按照上个月底的评估情况进行申请
     */
    @Scheduled(cron = "0 0 1 1,6-31 * ?")
    public void everydayEvaluation(){
        log.info("Task [Everyday Evaluation] starts");
        Range range = DatetimeUtils.month(DatetimeUtils.now().minusDays(1)); //1号算的是上个月的，其他时间算的是本月的
        List<String> users = businessRoleRepository.findByBusinessRole(BusinessRole.AG_SHOP);
        users.stream()
                .map(userCacheManager::get)
                .filter(cu-> Arrays.asList(
                BusinessRole.AG_SHOP,
                BusinessRole.AU_SHOP,
                BusinessRole.AG_WHS,
                BusinessRole.AU_WHS,
                BusinessRole.AG_AGENT).contains(cu.getHighestRole())) //只有这几种身份是每天
                .forEach(cu->advanceEvaluationService.evaluate(cu.getId(), range));
        log.info("Task [Everyday Evaluation] finished");
    }

    /**
     * 每月进行的资格评估
     * 2-5月不进行，因为至少需要5个月才能达标
     */
    @Scheduled(cron = "0 0 2 3 1,4-12 ?")
    public void everyMonthEvaluation(){
        log.info("Task [EveryMonth Evaluation] starts");
        Range range = DatetimeUtils.year(DatetimeUtils.now().minusMonths(1)); //1月算的是去年的，其他时间算的是今年的
        List<String> users = businessRoleRepository.findByBusinessRole(BusinessRole.AU_AGENT);
        users.stream()
                .map(userCacheManager::get)
                .filter(cu-> Arrays.asList(BusinessRole.AU_AGENT,
                        BusinessRole.MANAGER,
                        BusinessRole.AG_DIRECTOR).contains(cu.getHighestRole())) //只有这几种身份是每月
                .forEach(cu->advanceEvaluationService.evaluate(cu.getId(), range));
        log.info("Task [EveryMonth Evaluation] finished");
    }

    /**
     *
     *   年度评估，每年1月5日进行
     *   Q： 为什么不1月1号执行？
     *   A： 由于前一年12月的业绩要到1月1日0点之后才能完整结算。
     *   1月1日到1月4日 是给 12月刚刚成为获得经理申请资格的人员 进行审批流程的时间
     */
    @Scheduled(cron = "0 0 3 5 1  ?")
    public void everyYearEvaluation(){

        log.info("Task [EveryYear Evaluation] starts");
        Range range = DatetimeUtils.year(DatetimeUtils.now().minusMonths(1)); //依据去年

        log.info("[Starting Retain evaluation] ");
        performRetainEvaluations(range);
        log.warn("[Retain evaluation finished] ");

        log.info("[Starting Directors Promotion evaluation] ]");
        performDirectorsEvaluation(range);
        log.info("[Finishing Directors Promotion evaluation] ]");

        log.info("Task [EveryYear Evaluation] finished");
    }


    
    /**
     * 重新计算本年度的 总监和董事
     * @param range
     */
    private void performDirectorsEvaluation(Range range) {
        advanceEvaluationService.reevaluateAllDirectors(range);
    }

    /**
     * 依次判断经理，代理和批发商是否可以继续保持身份。如果不符合条件，执行降级
     * @param range
     */
    private void performRetainEvaluations(Range range){
        log.info("Task [Retain Evaluation] starts");
        retainEvaluationService.evaluateAll(range, BusinessRole.MANAGER);
        retainEvaluationService.evaluateAll(range, BusinessRole.AG_AGENT);
        retainEvaluationService.evaluateAll(range, BusinessRole.AG_WHS);
        // 由于可能发生了降级，所以需要重新计算 代理和批发是金还是银
        retainEvaluationService.recalculateAgAgent();
        retainEvaluationService.recalculateAgWhs();
        log.info("Task [Retain Evaluation] finished");

    }





}
